﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadLearn
{
    internal static class TaskDemo
    {
        public static void Go()
        {
            Task<int> t = new Task<int>(() => Sum(100));
            t.Start();
            t.Wait();
            Console.WriteLine(string.Format("The Sum is:{0}", t.Result));
            Console.ReadLine();
            
        }

        public static void TaskCacel()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            Task<int> t = new Task<int>(() => Sum(cts.Token, 1000000000), cts.Token);
            cts.Cancel();

            try
            {
                Console.WriteLine(string.Format("The sum is:" + t.Result));
            }
            catch(AggregateException x)
            {
                x.Handle(e => e is OperationCanceledException);
                Console.WriteLine("Sum was canceled");
            }
        }

        public static void TaskContinueWith()
        {
            Task<int> t = Task.Run(() => Sum(CancellationToken.None, 10000));
            Task cwt = t.ContinueWith(task => Console.WriteLine(string.Format("The Sum is:{0}", task.Result)));
            Console.ReadLine();
        }

        public static void TaskContinueWithMultiple()
        {
            Task<int> t = Task.Run(() => Sum(CancellationToken.None, 10000));
            Task cwt = t.ContinueWith(task => Console.WriteLine(string.Format("The Sum is:{0}", task.Result)),TaskContinuationOptions.OnlyOnRanToCompletion);
            t.ContinueWith(task => Console.WriteLine(string.Format("Sum threw:{0}", task.Exception.InnerException),TaskContinuationOptions.OnlyOnFaulted));
            t.ContinueWith(task => Console.WriteLine(string.Format("Sum was canceled", TaskContinuationOptions.OnlyOnCanceled)));
            Console.ReadLine();
        }

        public static void ChildTask()
        {
            Task<int[]> parentTask = new Task<int[]>(()=> {
                int[] result = new int[3];

                Console.WriteLine("start date=>" + DateTime.Now);

                new Task(() => {
                    
                    Console.WriteLine("start 1 date=>" + DateTime.Now);
                    Thread.Sleep(2000);
                    Console.WriteLine("end 1 date=>" + DateTime.Now);

                    result[0] = Sum(100);
                }, TaskCreationOptions.AttachedToParent).Start();

                Console.WriteLine("index 1 date=>" + DateTime.Now);

                new Task(() => { result[1] = Sum(200); Thread.Sleep(2000); }, TaskCreationOptions.AttachedToParent).Start();

                Console.WriteLine("index 2 date=>" + DateTime.Now);

                new Task(() => { result[2] = Sum(300); Thread.Sleep(2000); }, TaskCreationOptions.AttachedToParent).Start();

                Console.WriteLine("index 3 date=>" + DateTime.Now);

                Console.WriteLine("wait date:" + DateTime.Now);
                Console.WriteLine("index=>1,value=>" + result[0]);
                Console.WriteLine("index=>2,value=>" + result[1]);
                Console.WriteLine("index=>3,value=>" + result[2]);

                return result;
            });

            parentTask.ContinueWith((task) => Array.ForEach(task.Result, Console.WriteLine));
            parentTask.Start();

            Console.ReadLine();
        }

        public static void TaskFactory()
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                var tf = new TaskFactory<int>(
                    cts.Token,
                    TaskCreationOptions.AttachedToParent,
                    TaskContinuationOptions.ExecuteSynchronously,
                    TaskScheduler.Default);
                var childTasks = new[]
                {
                    tf.StartNew(()=>Sum(cts.Token,10000)),
                    tf.StartNew(()=>Sum(cts.Token,20000)),
                    tf.StartNew(()=>Sum(cts.Token,int.MaxValue))//太大，抛出OverflowException
                };
                //任何子任务抛出异常，就取消其它子任务
                for(int task=0;task<childTasks.Length;task++)
                {
                    childTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);
                }
                //所有子任务完成后，从未出错/未取消的任务获取返回的最大值
                //然后将最大值传给另一个任务显示最大结果
                tf.ContinueWhenAll(
                    childTasks,
                    completedTasks => completedTasks.Where(t => !t.IsCanceled && !t.IsFaulted).Max(t => t.Result),
                    CancellationToken.None).ContinueWith(t => Console.WriteLine("The maximum is:" + t.Result),
                    TaskContinuationOptions.ExecuteSynchronously);
            });

            parent.ContinueWith(p =>
            {
                StringBuilder sb = new StringBuilder("The following exception(s) occurred:" + Environment.NewLine);
                foreach (var e in p.Exception.Flatten().InnerExceptions)
                {
                    sb.Append(" " + e.GetType().ToString());
                }
                Console.WriteLine(sb.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);

            parent.Start();

            Console.ReadLine();
        } 

        private static int Sum(int n)
        {
            int sum = 0;
            for(;n>0;n--)
            {
                checked { sum += n; }
            }
            return sum;
        }

        private static int Sum(CancellationToken ct, int n)
        {
            int sum = 0;
            for (; n > 0; n--)
            {
                ct.ThrowIfCancellationRequested();
                checked { sum += n; }
            }
            return sum;
        }

    }
}
